from scipy.optimize import minimize
import numpy as np


def count_target(r, a, b, c, target):
    now = {
        'calorie': 0,
        'protein': 0,
        'fat': 0,
        'carbohydrate': 0
    }
    for i_a, item_a in enumerate(a):
        now['calorie'] += item_a['Calorie'] * r[i_a]
        now['protein'] += item_a['Protein'] * r[i_a]
        now['fat'] += item_a['Fat'] * r[i_a]
        now['carbohydrate'] += item_a['Carbohydrate'] * r[i_a]
    for i_b, item_b in enumerate(b):
        idx = i_b + len(a)
        now['calorie'] += item_b['Calorie'] * r[idx]
        now['protein'] += item_b['Protein'] * r[idx]
        now['fat'] += item_b['Fat'] * r[idx]
        now['carbohydrate'] += item_b['Carbohydrate'] * r[idx]
    for i_c, item_c in enumerate(c):
        idx = i_c + len(b) + len(a)
        now['calorie'] += item_c['Calorie'] * r[idx]
        now['protein'] += item_c['Protein'] * r[idx]
        now['fat'] += item_c['Fat'] * r[idx]
        now['carbohydrate'] += item_c['Carbohydrate'] * r[idx]

    return (now['protein'] / target['protein'] - 1) ** 2 + (now['fat'] / target['fat'] - 1) ** 2 + (
                now['carbohydrate'] / target['carbohydrate'] - 1) ** 2


def con_fun(r, a, b, c, target):
    now = {
        't': {
            'calorie': 0,
            'protein': 0,
            'fat': 0,
            'carbohydrate': 0
        },
        'r': {
            'calorie': 0,
            'protein': 0,
            'fat': 0,
            'carbohydrate': 0
        },
        'a': {
            'calorie': 0,
            'protein': 0,
            'fat': 0,
            'carbohydrate': 0
        },
        'ar': {
            'calorie': 0,
            'protein': 0,
            'fat': 0,
            'carbohydrate': 0
        },
        'b': {
            'calorie': 0,
            'protein': 0,
            'fat': 0,
            'carbohydrate': 0
        },
        'br': {
            'calorie': 0,
            'protein': 0,
            'fat': 0,
            'carbohydrate': 0
        },
        'c': {
            'calorie': 0,
            'protein': 0,
            'fat': 0,
            'carbohydrate': 0
        },
        'cr': {
            'calorie': 0,
            'protein': 0,
            'fat': 0,
            'carbohydrate': 0
        }
    }

    for i_a, item_a in enumerate(a):
        now['t']['calorie'] += item_a['Calorie'] * r[i_a]
        now['t']['protein'] += item_a['Protein'] * r[i_a]
        now['t']['fat'] += item_a['Fat'] * r[i_a]
        now['t']['carbohydrate'] += item_a['Carbohydrate'] * r[i_a]
        now['a']['calorie'] += item_a['Calorie'] * r[i_a]
        now['a']['protein'] += item_a['Protein'] * r[i_a]
        now['a']['fat'] += item_a['Fat'] * r[i_a]
        now['a']['carbohydrate'] += item_a['Carbohydrate'] * r[i_a]
    for i_b, item_b in enumerate(b):
        idx = i_b + len(a)
        now['t']['calorie'] += item_b['Calorie'] * r[idx]
        now['t']['protein'] += item_b['Protein'] * r[idx]
        now['t']['fat'] += item_b['Fat'] * r[idx]
        now['t']['carbohydrate'] += item_b['Carbohydrate'] * r[idx]
        now['b']['calorie'] += item_b['Calorie'] * r[idx]
        now['b']['protein'] += item_b['Protein'] * r[idx]
        now['b']['fat'] += item_b['Fat'] * r[idx]
        now['b']['carbohydrate'] += item_b['Carbohydrate'] * r[idx]
    for i_c, item_c in enumerate(c):
        idx = i_c + len(b) + len(a)
        now['t']['calorie'] += item_c['Calorie'] * r[idx]
        now['t']['protein'] += item_c['Protein'] * r[idx]
        now['t']['fat'] += item_c['Fat'] * r[idx]
        now['t']['carbohydrate'] += item_c['Carbohydrate'] * r[idx]
        now['c']['calorie'] += item_c['Calorie'] * r[idx]
        now['c']['protein'] += item_c['Protein'] * r[idx]
        now['c']['fat'] += item_c['Fat'] * r[idx]
        now['c']['carbohydrate'] += item_c['Carbohydrate'] * r[idx]

    now['r']['calorie'] = now['t']['calorie'] / target['calorie']
    now['r']['protein'] = now['t']['protein'] * 4 / target['calorie']
    now['r']['fat'] = now['t']['fat'] * 9 / target['calorie']
    now['r']['carbohydrate'] = now['t']['carbohydrate'] * 4 / target['calorie']

    now['ar']['calorie'] = now['a']['calorie'] / target['calorie']
    now['ar']['protein'] = now['a']['protein'] * 4 / target['calorie']
    now['ar']['fat'] = now['a']['fat'] * 9 / target['calorie']
    now['ar']['carbohydrate'] = now['a']['carbohydrate'] * 4 / target['calorie']

    now['br']['calorie'] = now['b']['calorie'] / target['calorie']
    now['br']['protein'] = now['b']['protein'] * 4 / target['calorie']
    now['br']['fat'] = now['b']['fat'] * 9 / target['calorie']
    now['br']['carbohydrate'] = now['b']['carbohydrate'] * 4 / target['calorie']

    now['cr']['calorie'] = now['c']['calorie'] / target['calorie']
    now['cr']['protein'] = now['c']['protein'] * 4 / target['calorie']
    now['cr']['fat'] = now['c']['fat'] * 9 / target['calorie']
    now['cr']['carbohydrate'] = now['c']['carbohydrate'] * 4 / target['calorie']

    # t = {'calorie': round(float(now['r']['calorie']), 2), 'protein': round(float(now['r']['protein']), 2),
    #      'fat': round(float(now['r']['fat']), 2), 'carbohydrate': round(float(now['r']['carbohydrate']), 2)}
    # print(t)
    return now


def lp_problem(a, b, c, target):
    target['protein'] = target['calorie'] * 0.133 / 4
    target['fat'] = target['calorie'] * 0.267 / 9
    target['carbohydrate'] = target['calorie'] * 0.6 / 4
    print(target)

    n = len(a) + len(b) + len(c)

    # 变量范围
    bounds = []
    # 谷薯类
    type1 = (0.25, 2)
    # 其他
    type2 = (0.5, 5)
    for item in a + b + c:
        if (item['Type'] == "谷薯类"):
            bounds.append(type1)
        else:
            bounds.append(type2)

    print(bounds)

    # 设置初始猜测值
    x0 = np.ones(n)

    # 构造约束条件
    cons = [
        {'type': 'ineq', 'fun': lambda r: con_fun(r, a, b, c, target)['t']['calorie'] - (target['calorie'] - 50)},
        {'type': 'ineq', 'fun': lambda r: (target['calorie'] + 50) - con_fun(r, a, b, c, target)['t']['calorie']},
        # {'type': 'ineq', 'fun': lambda r: con_fun(r, a, b, c, target)['r']['protein'] - 0.15},
        # {'type': 'ineq', 'fun': lambda r: 0.1 - con_fun(r, a, b, c, target)['r']['protein']},
        {'type': 'ineq', 'fun': lambda r: con_fun(r, a, b, c, target)['r']['fat'] - 0.2},
        {'type': 'ineq', 'fun': lambda r: 0.3 - con_fun(r, a, b, c, target)['r']['fat']},
        {'type': 'ineq', 'fun': lambda r: con_fun(r, a, b, c, target)['r']['carbohydrate'] - 0.5},
        {'type': 'ineq', 'fun': lambda r: 0.65 - con_fun(r, a, b, c, target)['r']['carbohydrate']},

        {'type': 'ineq', 'fun': lambda r: con_fun(r, a, b, c, target)['ar']['calorie'] - 0.29},
        {'type': 'ineq', 'fun': lambda r: 0.31 - con_fun(r, a, b, c, target)['ar']['calorie']},
        {'type': 'ineq', 'fun': lambda r: con_fun(r, a, b, c, target)['br']['calorie'] - 0.39},
        {'type': 'ineq', 'fun': lambda r: 0.41 - con_fun(r, a, b, c, target)['ar']['calorie']},
        {'type': 'ineq', 'fun': lambda r: con_fun(r, a, b, c, target)['cr']['calorie'] - 0.29},
        {'type': 'ineq', 'fun': lambda r: 0.31 - con_fun(r, a, b, c, target)['cr']['calorie']},

        # {'type': 'ineq', 'fun': lambda r: con_fun(r, a, b, c, target)['ar']['fat'] - 0.2},
        # {'type': 'ineq', 'fun': lambda r: 0.3 - con_fun(r, a, b, c, target)['ar']['fat']},
        # {'type': 'ineq', 'fun': lambda r: con_fun(r, a, b, c, target)['ar']['carbohydrate'] - 0.25},
        # {'type': 'ineq', 'fun': lambda r: 0.35 - con_fun(r, a, b, c, target)['ar']['carbohydrate']},
        # {'type': 'ineq', 'fun': lambda r: con_fun(r, a, b, c, target)['br']['fat'] - 0.2},
        # {'type': 'ineq', 'fun': lambda r: 0.3 - con_fun(r, a, b, c, target)['br']['fat']},
        # {'type': 'ineq', 'fun': lambda r: con_fun(r, a, b, c, target)['br']['carbohydrate'] - 0.35},
        # {'type': 'ineq', 'fun': lambda r: 0.45 - con_fun(r, a, b, c, target)['br']['carbohydrate']},
        # {'type': 'ineq', 'fun': lambda r: con_fun(r, a, b, c, target)['cr']['fat'] - 0.2},
        # {'type': 'ineq', 'fun': lambda r: 0.3 - con_fun(r, a, b, c, target)['cr']['fat']},
        # {'type': 'ineq', 'fun': lambda r: con_fun(r, a, b, c, target)['cr']['carbohydrate'] - 0.4},
        # {'type': 'ineq', 'fun': lambda r: 0.7 - con_fun(r, a, b, c, target)['cr']['carbohydrate']}
    ]

    result = minimize(
        fun=count_target,
        x0=x0,
        args=(a, b, c, target),
        method='SLSQP',
        bounds=bounds,
        constraints=cons
    )

    if result.success:
        print("最优解:", [round(float(val), 2) for val in result.x])
        return [round(float(val), 2) for val in result.x]
    else:
        print("未找到可行解:", result.message)

def data_correct(list):
    for item in list:
        r = 100 / item['Per_Edible']
        item['Calorie'] = item['Calorie'] * r
        item['Protein'] = item['Protein'] * r
        item['Fat'] = item['Fat'] * r
        item['Carbohydrate'] = item['Carbohydrate'] * r
        item['Per_Edible'] = 100
    return list


if __name__ == '__main__':
    a = [
        {
            "R_Name": "韭菜豆渣饼",
            "Type": "谷薯类",
            "Calorie": 333.0,
            "Protein": 21.1,
            "Fat": 13.2,
            "Carbohydrate": 34.8,
            "Per_Edible": 259.0
        },
        {
            "R_Name": "韭菜苔炒鸡蛋",
            "Type": "蛋类",
            "Calorie": 192.0,
            "Protein": 15.3,
            "Fat": 12.0,
            "Carbohydrate": 7.0,
            "Per_Edible": 188.0
        },
        {
            "R_Name": "薄皮菠菜饼",
            "Type": "蔬菜",
            "Calorie": 43.0,
            "Protein": 4.8,
            "Fat": 0.8,
            "Carbohydrate": 4.7,
            "Per_Edible": 110.0
        },
        {
            "R_Name": "草莓糙米粥",
            "Type": "谷薯类",
            "Calorie": 114.0,
            "Protein": 2.6,
            "Fat": 0.9,
            "Carbohydrate": 24.6,
            "Per_Edible": 260.0
        }
    ]
    b = [
        {
            "R_Name": "小油菜面皮汤",
            "Type": "谷薯类",
            "Calorie": 134.0,
            "Protein": 6.3,
            "Fat": 5.8,
            "Carbohydrate": 14.6,
            "Per_Edible": 150.0
        },
        {
            "R_Name": "菠萝炒鸡翅",
            "Type": "畜禽肉类",
            "Calorie": 322.0,
            "Protein": 19.8,
            "Fat": 14.6,
            "Carbohydrate": 28.1,
            "Per_Edible": 205.0
        },
        {
            "R_Name": "油菜泥",
            "Type": "蔬菜",
            "Calorie": 7.0,
            "Protein": 0.7,
            "Fat": 0.3,
            "Carbohydrate": 1.0,
            "Per_Edible": 50.0
        }
    ]
    c = [
        {
            "R_Name": "芦笋土豆泥",
            "Type": "谷薯类",
            "Calorie": 51.0,
            "Protein": 2.6,
            "Fat": 0.2,
            "Carbohydrate": 10.6,
            "Per_Edible": 100.0
        },
        {
            "R_Name": "糖醋大鲤鱼",
            "Type": "鱼虾类",
            "Calorie": 99.0,
            "Protein": 14.1,
            "Fat": 3.3,
            "Carbohydrate": 3.4,
            "Per_Edible": 83.0
        },
        {
            "R_Name": "凉拌血蚶",
            "Type": "蔬菜",
            "Calorie": 131.0,
            "Protein": 10.4,
            "Fat": 6.8,
            "Carbohydrate": 7.1,
            "Per_Edible": 122.0
        }
    ]
    a = data_correct(a)
    b = data_correct(b)
    c = data_correct(c)
    target = {'calorie': 2197.7}
    lp_problem(a, b, c, target)
